package emulator.shell.GUI.graph;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Stroke;

import emulator.history.BitStateChange;
import emulator.history.BitStateHistory;

public class BitGraphLine
{
	private String label;
	private BitStateHistory stateHistory;
	private Color color = Color.black;
	private Stroke knownValueStroke = new BasicStroke(3f);
	private Stroke unknownValueStroke = new BasicStroke(3f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL, 0f, new float[]{9}, 0f);
	private int positionIndex = 0;
	
	public String getLabel()
	{
		return label;
	}
	
	public BitGraphLine setLabel(String label)
	{
		this.label = label;
		return this;
	}
	
	public BitStateHistory getStateHistory()
	{
		return stateHistory;
	}
	
	public BitGraphLine setStateHistory(BitStateHistory stateHistory)
	{
		this.stateHistory = stateHistory;
		return this;
	}
	
	public Color getColor()
	{
		return color;
	}
	
	public BitGraphLine setColor(Color color)
	{
		this.color = color;
		return this;
	}
	
	public int getPositionIndex()
	{
		return positionIndex;
	}
	
	public BitGraphLine setPositionIndex(int positionIndex)
	{
		this.positionIndex = positionIndex;
		return this;
	}

	public Stroke getStroke()
	{
		return knownValueStroke;
	}

	public BitGraphLine setStroke(Stroke stroke)
	{
		this.knownValueStroke = stroke;
		return this;
	}

	public void draw(Graphics2D g2, long tickBegin, long tickEnd, int borderGapLeft, int borderGapTop, int lineGap, int width, double lineHeight)
	{
		if (stateHistory != null)
		{
			int yBase = (int)(borderGapTop + positionIndex * (lineHeight + lineGap)); 
			Stroke oldStroke = g2.getStroke();
			g2.setColor(color);
			BitStateChange previousState = stateHistory.getLessOrEqualElement(tickBegin);
			g2.setStroke(previousState != null ? knownValueStroke : unknownValueStroke);
			BitStateChange [] states = stateHistory.getRange(tickBegin, tickEnd-1);
			if (states.length == 0)
			{
				if (previousState != null)
				{
					int y = previousState.getValue() ? yBase : (int)(yBase + lineHeight);
					g2.drawLine(borderGapLeft, y, (int)(borderGapLeft + width), y);
				}
				else
				{
					BitStateChange nextState = stateHistory.getGreaterOrEqualElement(tickEnd);
					if (nextState != null)
					{
						int y = nextState.getValue() ? (int)(yBase + lineHeight) : yBase;
						g2.drawLine(borderGapLeft, y, (int)(borderGapLeft + width), y);
					}
				}
			}
			else
			{
				double lastX = borderGapLeft;
				double scaleX = (double)width / (tickEnd - tickBegin);
				for (int i = 0; i < states.length; i++)
				{
					double x = borderGapLeft + scaleX * (states[i].getTick() - tickBegin);
					int y = states[i].getValue() ? (int)(yBase + lineHeight) : yBase;
					g2.drawLine((int)lastX, y, (int)x, y);
					g2.setStroke(knownValueStroke);
					g2.drawLine((int)x, yBase, (int)x, (int)(yBase + lineHeight));
					lastX = x;
				}
				int y = states[states.length-1].getValue() ? yBase : (int)(yBase + lineHeight);
				g2.drawLine((int)lastX, y, borderGapLeft + width, y);
			}
			g2.setStroke(oldStroke);
		}
	}
}
